package com.shenma2009;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shenma2009.pojo.TbHero;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;

/**
 * @author 军哥
 * @version 1.0
 * @description: EsTestApp
 * @date 2023/8/20 9:18
 */

@SpringBootTest
public class EsTestApp {

    @Autowired
    RestHighLevelClient restHighLevelClient;

    /**
     * @description 创建索引
     * @author 军哥
     * @date 2023/8/20 13:00
     * @version 1.0
     */
    @Test
    public void createIndex() throws IOException {
        // 定义索引请求
        String indexName = "tb_hero";
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);

        // 定义索引映射
        XContentBuilder mapping = XContentFactory.jsonBuilder();
        mapping.startObject()
                .startObject("properties")
                .startObject("userId").field("type","long").endObject()
                .startObject("userName").field("type","keyword").endObject()
                .startObject("age").field("type","long").endObject()
                .startObject("sex").field("type","keyword").endObject()
                .startObject("userTech").field("type","text").field("analyzer", "ik_smart").endObject()
                .endObject()
                .endObject();

        createIndexRequest.mapping("_doc", mapping);

        // 创建索引
        CreateIndexResponse response = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        boolean acknowledged = response.isAcknowledged();
        System.out.println("Mapping creation acknowledged: " + acknowledged);

        // 获取索引的状态
        GetIndexResponse indexResponse = restHighLevelClient.indices().get(new GetIndexRequest(indexName), RequestOptions.DEFAULT);
        System.out.println(indexResponse.getAliases());
        System.out.println(indexResponse.getMappings().toString());
        System.out.println(indexResponse.getSettings());
    }

    /**
     * @description 删除索引
     * @author 军哥
     * @date 2023/8/20 14:44
     * @version 1.0
     */
    @Test
    public void deleteIndex() throws IOException {
        String indexName = "tb_hero";

        // 判断索引是否存在
        boolean exists = restHighLevelClient.indices().exists(new GetIndexRequest(indexName), RequestOptions.DEFAULT);
        if(!exists) {
            System.out.println("索引不存在："+indexName);
            return;
        }
        // 删除索引
        AcknowledgedResponse delete = restHighLevelClient.indices().delete(new DeleteIndexRequest(indexName), RequestOptions.DEFAULT);
        if(delete.isAcknowledged()) {
            System.out.println("索引已经删除");
        }
        else {
            System.out.println("索引删除失败");
        }
    }

    /**
     * @description 增加记录
     * @author 军哥
     * @date 2023/8/20 17:18
     * @version 1.0
     */
    @Test
    public void insertDoc() throws IOException {
        String indexName = "tb_hero";

        TbHero tbHero = new TbHero();
        tbHero.setUserId(101);
        tbHero.setUserName("鲁智深");
        tbHero.setAge(33);
        tbHero.setSex("男");
        tbHero.setUserTech("倒拔垂杨柳");

        IndexRequest indexRequest = new IndexRequest();
        indexRequest.index(indexName).id(""+tbHero.getUserId());

        ObjectMapper mapper = new ObjectMapper();
        String s = mapper.writeValueAsString(tbHero);

        indexRequest.source(s, XContentType.JSON);

        IndexResponse index = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        System.out.println("" + index.toString());
    }

    /**
     * @description 更新文档
     * @author 军哥
     * @date 2023/8/20 17:35
     * @version 1.0
     */
    @Test
    public void updateDoc() throws IOException {
        String indexName = "tb_hero";

        UpdateRequest updateRequest = new UpdateRequest();
        updateRequest.index(indexName).id("101");
        updateRequest.doc(XContentType.JSON, "userTech", "拳打镇关西");

        UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);

        System.out.println(response.toString());
    }


    /**
     * @description 根据ID读取单个文档
     * @author 军哥
     * @date 2023/8/20 17:46
     * @version 1.0
     */
    @Test
    public void selectDoc() throws IOException {
        String indexName = "tb_hero";

        GetRequest request = new GetRequest();
        request.index(indexName).id("101");
        GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);

        System.out.println(response.getSourceAsString());

        ObjectMapper objectMapper = new ObjectMapper();
        TbHero tbHero = objectMapper.readValue(response.getSourceAsString(), TbHero.class);
        System.out.println(tbHero.toString());

    }

    /**
     * @description 删除单个文档
     * @author 军哥
     * @date 2023/8/20 17:52
     * @version 1.0
     */
    @Test
    public void deleteDoc() throws IOException {
        String indexName = "tb_hero";

        DeleteRequest request = new DeleteRequest();
        request.index(indexName).id("101");

        DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT);

        System.out.println(response.toString());

    }

    /**
     * @description 批量插入文档
     * @author 军哥
     * @date 2023/8/20 17:52
     * @version 1.0
     */

    @Test
    public void insertDocs() throws IOException {
        // 索引名字
        String indexName = "tb_hero";

        // 准备多个数据
        ArrayList<TbHero> tbHeroes = new ArrayList<>();

        TbHero tbHero1 = new TbHero();
        tbHero1.setUserId(101);
        tbHero1.setUserName("鲁智深");
        tbHero1.setSex("男");
        tbHero1.setAge(33);
        tbHero1.setUserTech("倒拔垂杨柳");

        TbHero tbHero2 = new TbHero();
        tbHero2.setUserId(102);
        tbHero2.setUserName("武松");
        tbHero2.setSex("男");
        tbHero2.setAge(33);
        tbHero2.setUserTech("景阳冈打虎");

        tbHeroes.add(tbHero1);
        tbHeroes.add(tbHero2);

        // 准备请求
        BulkRequest bulkRequest = new BulkRequest();
        ObjectMapper mapper = new ObjectMapper();

        tbHeroes.forEach(item -> {
            IndexRequest indexRequest = new IndexRequest();

            String s = null;
            try {
                indexRequest.index(indexName).id(""+item.getUserId());

                s = mapper.writeValueAsString(item);
                indexRequest.source(s, XContentType.JSON);

                bulkRequest.add(indexRequest);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        });

        BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(response.toString());
    }

    /**
     * @description 批量删除
     * @author 军哥
     * @date 2023/8/20 18:20
     * @version 1.0
     */
    @Test
    public void deleteDocs() throws IOException {
        // 索引名字
        String indexName = "tb_hero";

        BulkRequest bulkRequest = new BulkRequest();

        bulkRequest.add(new DeleteRequest().index(indexName).id("101"));
        bulkRequest.add(new DeleteRequest().index(indexName).id("102"));

        BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(response.toString());
    }

    /**
     * @description 全量查询
     * @author 军哥
     * @date 2023/8/20 18:26
     * @version 1.0
     */
    @Test
    public void queryAll() throws IOException {
        // 索引名字
        String indexName = "tb_hero";

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());

        searchRequest.source(searchSourceBuilder);

        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        TotalHits total = response.getHits().getTotalHits();
        System.out.println("总记录数为："+total);

        ObjectMapper mapper = new ObjectMapper();
        SearchHit[] hits = response.getHits().getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            TbHero tbHero = mapper.readValue(source, TbHero.class);

            System.out.println(tbHero.toString());
        }
    }

    /**
     * @description 精确查询+分页+排序+字段查询
     * @author 军哥
     * @date 2023/8/20 18:42
     * @version 1.0
     */
    @Test
    public void termQuery() throws IOException {
        // 索引名字
        String indexName = "tb_hero";

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.termQuery("sex", "男"));

        // 分页+排序
        builder.from(0).size(10).sort("userId", SortOrder.DESC);

        // 字段查询
        String includes[] = {"userName", "sex"};
        String excludes[] = {"sex"};
        builder.fetchSource(includes, excludes);

        searchRequest.source(builder);

        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        TotalHits total = response.getHits().getTotalHits();
        System.out.println("总记录数为："+total);

        ObjectMapper mapper = new ObjectMapper();
        SearchHit[] hits = response.getHits().getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            TbHero tbHero = mapper.readValue(source, TbHero.class);

            System.out.println(tbHero.toString());
        }
    }

    /**
     * @description 多条件查询
     * @author 军哥
     * @date 2023/8/20 21:03
     * @version 1.0
     */
    @Test
    public void boolQuery() throws IOException {
        // 索引名字
        String indexName = "tb_hero";

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder builder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        boolQueryBuilder.must(QueryBuilders.termQuery("age", 33));
        boolQueryBuilder.must(QueryBuilders.termQuery("userName", "武松"));

        builder.query(boolQueryBuilder);
        searchRequest.source(builder);

        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        TotalHits total = response.getHits().getTotalHits();
        System.out.println("总记录数为："+total);

        ObjectMapper mapper = new ObjectMapper();
        SearchHit[] hits = response.getHits().getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            TbHero tbHero = mapper.readValue(source, TbHero.class);

            System.out.println(tbHero.toString());
        }
    }

    /**
     * @description 区间查询
     * @author 军哥
     * @date 2023/8/20 21:12
     * @version 1.0
     */
    @Test
    public void rangeQuery() throws IOException {
        // 索引名字
        String indexName = "tb_hero";

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder builder = new SearchSourceBuilder();

        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("userId").lte(200).gte(100);
        builder.query(rangeQueryBuilder);

        searchRequest.source(builder);

        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        TotalHits total = response.getHits().getTotalHits();
        System.out.println("总记录数为："+total);

        ObjectMapper mapper = new ObjectMapper();
        SearchHit[] hits = response.getHits().getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            TbHero tbHero = mapper.readValue(source, TbHero.class);

            System.out.println(tbHero.toString());
        }
    }

    /**
     * @description 模糊查询
     * @author 军哥
     * @date 2023/8/20 21:21
     * @version 1.0
     */
    @Test
    public void fuzzyQuery() throws IOException {
        // 索引名字
        String indexName = "tb_hero";

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder builder = new SearchSourceBuilder();

        FuzzyQueryBuilder fuzziness = QueryBuilders.fuzzyQuery("userName", "武").fuzziness(Fuzziness.ONE);
        builder.query(fuzziness);

        searchRequest.source(builder);

        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        TotalHits total = response.getHits().getTotalHits();
        System.out.println("总记录数为："+total);

        ObjectMapper mapper = new ObjectMapper();
        SearchHit[] hits = response.getHits().getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            TbHero tbHero = mapper.readValue(source, TbHero.class);

            System.out.println(tbHero.toString());
        }
    }

    /**
     * @description 高亮查询
     * @author 军哥
     * @date 2023/8/20 21:36
     * @version 1.0
     */
    @Test
    public void highLightQuery() throws IOException {
        // 索引名字
        String indexName = "tb_hero";

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(indexName);

        SearchSourceBuilder builder = new SearchSourceBuilder();

        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("userTech", "柳虎");

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font color='red'>");
        highlightBuilder.postTags("</font>");
        highlightBuilder.field("userTech");
        builder.highlighter(highlightBuilder);

        builder.query(matchQueryBuilder);

        searchRequest.source(builder);

        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        TotalHits total = response.getHits().getTotalHits();
        System.out.println("总记录数为："+total);

        ObjectMapper mapper = new ObjectMapper();
        SearchHit[] hits = response.getHits().getHits();
        for (SearchHit hit : hits) {
            String source = hit.getSourceAsString();
            TbHero tbHero = mapper.readValue(source, TbHero.class);

            HighlightField techName = hit.getHighlightFields().get("userTech");
            if(techName != null) {
                String string = techName.getFragments()[0].string();
                tbHero.setUserTech(string);
            }

            System.out.println(tbHero.toString());
        }

    }
}
